package appli;

import ihm.AppliWindow;

import java.awt.Color;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.util.ArrayList;
import java.util.List;
import javax.swing.JPanel;

import org.janusproject.kernel.agent.Agent;
import org.janusproject.kernel.agent.Kernel;
import org.janusproject.kernel.agent.Kernels;

import appli.utils.Config;
import sma.agents.GoalAgent;
import sma.agents.MassCenterAgent;
import sma.agents.ObstacleAgent;
import sma.agents.DecisiveAgent;
import sma.agents.StandartAgent;

/**
 * smaLauncher is the launcher for all multi-agent matter.
 * It will handle kernel and all agents
 *
 * Since 0.2 version, we create a certain amount of agent per existing telemeter.
 * Agents take part of different telemeter group 
 * 
 * @author Etienne Sainton
 * @author Arnaud Schaeffer
 * @since 0.1
 * @version 0.2
 */
public class SmaLauncher {
        /**
         * MultiAgent kernel
         */
        private Kernel kernel;

        /**
         * Agents environment
         */
        private sma.environment.LocalEnvironment environment;

        /**
         * Agent which defines where the vehicule shoud go
         */
        private MassCenterAgent massCenterAgent;

        /**
         * List of all agents that we create
         */
        private List<sma.agents.StandartAgent> listAgents = new ArrayList<StandartAgent>();
        
        /**
         * List of obstacle agents
         */
        private List<List<sma.agents.ObstacleAgent>> listObstacleAgents = new ArrayList<List<ObstacleAgent>>();
        
        /**
         * List of goal agents
         */
        private List<sma.agents.GoalAgent> listGoalAgents = new ArrayList<GoalAgent>();

        /**
         * Send commands to the vehicule thread
         */
        private Direction commande;
        
        /**
         * Constructor. 
         * It start Janus kernel, then all agents needed for the application
         * in this order :
         * GoalAgent
         * MassCenterAgent

         * 
         * @param _env agents environment 
         */
        public SmaLauncher(sma.environment.LocalEnvironment _env) {
                //Affects environment :
                this.environment = _env;

                //Affects kernel
                kernel = Kernels.get(false);
               
        }
        
        /**
         * Lance le SMA
         */
        public void initSma(){
        	        	
        	 //Creates GoalAgent
            for(Telemeter telem : Launcher.listTelemeters) {
            	GoalAgent tmp = new GoalAgent(environment, telem.getPort());
                listGoalAgents.add(tmp);
                listAgents.add(tmp);
            }
            
            //Creates GravityAgent
            massCenterAgent = new MassCenterAgent(environment);
            listAgents.add(massCenterAgent);
        }

        /**
         * Start simulation
         * start all agents
         * @param _gui graphic user interface
         */
        public void startSimu(AppliWindow _gui) {
        	
        	int inc = 0;
        	
        	//For each telemeter :
        	Color agentColor;
        	for(Telemeter telem : Launcher.listTelemeters) {
        		//Agent color depending on telemeter
                if(inc == 0)
                	agentColor = Color.YELLOW;
                else
                	agentColor = Color.MAGENTA;
                
                //First start goalAgent
                kernel.launchLightAgent(listGoalAgents.get(inc), "Goal", _gui.getMassCenterPanel());

                
                //Then decisiveAgents
                for (int i = 0; i < Config.decisiveAgentNb; ++i) {
                        DecisiveAgent tmpAgent = new DecisiveAgent(this.environment, telem.getPort());
							
                        tmpAgent.getBody().setColor(agentColor);
                        listAgents.add(tmpAgent);
                     
                        kernel.launchLightAgent(tmpAgent, "DecisiveAgent_" + i, _gui.getMassCenterPanel(),
                        		Config.SMA_CONSTANTE.avoidsDecisive,
    							Config.SMA_CONSTANTE.goalAttraction,
    							Config.SMA_CONSTANTE.avoidsObstacle,
    							Config.SMA_CONSTANTE.deltaT);
                }

                //Initialize the obstacleAgent list
                listObstacleAgents.add(new ArrayList<ObstacleAgent>());
                
                //Decesive agent color depending on telemeter
                if(inc == 0)
                	agentColor = Color.CYAN;
                else
                	agentColor = Color.PINK;
                
                //Create obstacleAgent
                for (int i = 1; i <= 181; ++i) {
                        ObstacleAgent tmpAgent = new ObstacleAgent(this.environment,_gui, i, telem.getPort(), telem.getRotation());
                        tmpAgent.getBody().setColor(agentColor);
                        listAgents.add(tmpAgent);
                        listObstacleAgents.get(inc).add(tmpAgent);
                        kernel.launchLightAgent(tmpAgent, "ObstacleAgent_" + i + telem.getPort(), _gui.getAgents(inc), true);
                }
                
                inc++;
        	}
        	
        	//At last, we start ONE gravityAgent
            kernel.launchLightAgent(massCenterAgent, "MassCenter", _gui.getMassCenterPanel(), Launcher.direction, Config.SMA_CONSTANTE.k);
        	//kernel.launchLightAgent(massCenterAgent, "MassCenter", commande);
        }

        
        
        /**
         * Launch decisiveAgent
         * @param _gui 
         */
        public void launchDecisiveAgents(AppliWindow _gui){
        	
    		int inc = 0;
        	
        	//For each telemeter :
        	Color agentColor;
        	for(Telemeter telem : Launcher.listTelemeters) {
        		
        		//Agent color depending on telemeter
                if(inc == 0)
                	agentColor = Color.YELLOW;
                else
                	agentColor = Color.MAGENTA;
                
	            for (int i = 0; i < Config.decisiveAgentNb; ++i) {
	            	if(Config.PARK_MODE){
	            		DecisiveAgent tmpAgent = new DecisiveAgent(this.environment, telem.getPort());
	                    tmpAgent.getBody().setColor(agentColor);
	                    listAgents.add(tmpAgent);
	                    kernel.launchLightAgent(tmpAgent, "DecisiveAgent_" + i, _gui.getMassCenterPanel(),
		                    Config.SMA_CONSTANTE_PARK.avoidsDecisive,
		                    Config.SMA_CONSTANTE_PARK.goalAttraction,
		                    Config.SMA_CONSTANTE_PARK.avoidsObstacle,
		                    Config.SMA_CONSTANTE_PARK.deltaT);
	            	}
                    else{
                    	DecisiveAgent tmpAgent = new DecisiveAgent(this.environment, telem.getPort());
	                    tmpAgent.getBody().setColor(agentColor);
	                    listAgents.add(tmpAgent);
	                    kernel.launchLightAgent(tmpAgent, "DecisiveAgent_" + i, _gui.getMassCenterPanel(),
		                    Config.SMA_CONSTANTE.avoidsDecisive,
		                    Config.SMA_CONSTANTE.goalAttraction,
		                    Config.SMA_CONSTANTE.avoidsObstacle,
		                    Config.SMA_CONSTANTE.deltaT);
                    }
	            }
	            
	            inc++;
        	}
        }
        
        
        /**
         * Returns goalAgent
         * @param i telemeter number
         * 
         * @return GoalAgent
         */
        public sma.agents.GoalAgent getGoalAgent(int i) {
                return this.listGoalAgents.get(i);
        }

        /**
         * Return agents used by our multiagent system (excluding some JANUS agent
         * as Kernel, Scheduler...)
         * this list need to be synchronized
         * 
         * @return listAgents
         */
        public List<sma.agents.StandartAgent> getListeAgents() {
                return listAgents;
        }

        /**
         * @return the kernel
         */
        public Kernel getKernel() {
                return kernel;
        }

		/**
		 * @param i number
		 * @return the listeAgentsObstacle
		 */
		public List<sma.agents.ObstacleAgent> getListAgentsObstacle(int i) {
			return listObstacleAgents.get(i);
		}

		/**
		 * Stop all decisivesAgent
		 */
		public void stopDecisiveAgents() {
			sma.agents.StandartAgent[] tabAgent = new sma.agents.StandartAgent[listAgents.size()];

			int index = 0;
			for(sma.agents.StandartAgent agent : listAgents){
				if(agent instanceof sma.agents.DecisiveAgent){
					agent.getGuiChannel().deleteAgent();
					tabAgent[index] = agent;
				}else{
					tabAgent[index] = null;
				}
				index++;
			}
			
			for(int i=0; i<tabAgent.length; i++){
				if(tabAgent[i] != null){
					listAgents.remove(tabAgent[i]);
				}
			}
			
		}


}
